package tcln.sors.model.core.criteria;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Date;

/**
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public class SearchCriterion implements Serializable {
    private static final long serialVersionUID = 1L;

    private String property;
    private SearchOperator operator;
    private String[] stringValues;
    private Date[] dateValues;
    private Number[] numberValues;
    private Enum<?>[] enumValues;

    /**
     * @deprecated this constructor is required by GWT Serializer. Don't use it manually.
     */
    @Deprecated
    public SearchCriterion() {
    }

    /**
     * @param property
     * @param operator
     */
    public SearchCriterion(String property, SearchOperator operator) {
        this.property = property;
        this.operator = operator;
    }

    /**
     * @param property
     * @param operator
     * @param values
     */
    public SearchCriterion(String property, SearchOperator operator, String... values) {
        this(property, operator);
        this.stringValues = values;
    }

    /**
     * @param property
     * @param operator
     * @param values
     */
    public SearchCriterion(String property, SearchOperator operator, Date... values) {
        this(property, operator);
        this.dateValues = values;
    }

    /**
     * @param property
     * @param operator
     * @param values
     */
    public SearchCriterion(String property, SearchOperator operator, Number... values) {
        this(property, operator);
        this.numberValues = values;
    }

    /**
     * @param property
     * @param operator
     * @param values
     */
    public SearchCriterion(String property, SearchOperator operator, Enum<?>... values) {
        this(property, operator);
        this.enumValues = values;
    }

    /**
     * Returns current value of {@link #property}.
     * 
     * @return the {@link #property}.
     */
    public String getProperty() {
        return property;
    }

    /**
     * Returns current value of {@link #operator}.
     * 
     * @return the {@link #operator}.
     */
    public SearchOperator getOperator() {
        return operator;
    }

    /**
     * Returns current value of {@link #values}.
     * 
     * @return the {@link #values}.
     */
    public Object[] getValues() {
        if (containsStringValues()) {
            return stringValues;
        } else if (containsDateValues()) {
            return dateValues;
        } else if (containsNumericValues()) {
            return numberValues;
        } else if (containsEnumValues()) {
            return enumValues;
        } else {
            return null;
        }
    }
    
    public <T extends Serializable> T[] getValues(Class<T> valueClass) {
        return (T[]) getValues();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        Object[] values = getValues();
        Object[] params = values != null ? values : new Object[0];
        String fullOperator = MessageFormat.format(operator.getFormatPattern(), params);
        builder.append(property).append(" ").append(fullOperator);
        return builder.toString();
    }

    /**
     * Checks if this criterion is about to compare a property with string values.
     * 
     * @return
     */
    public final boolean containsStringValues() {
        return stringValues != null && stringValues.length > 0;
    }

    /**
     * Checks if this criterion is about to compare a property with numeric values.
     * 
     * @return
     */
    public final boolean containsNumericValues() {
        return numberValues != null && numberValues.length > 0;
    }

    /**
     * Checks if this criterion is about to compare a property with date values.
     * 
     * @return
     */
    public final boolean containsDateValues() {
        return dateValues != null && dateValues.length > 0;
    }

    /**
     * Checks if this criterion is about to compare a property with enum values.
     * 
     * @return
     */
    public final boolean containsEnumValues() {
        return enumValues != null && enumValues.length > 0;
    }
}
